package cn.com.chengmandian.bike.service.impl;

import cn.com.chengmandian.agent.utils.AuthUtil;
import cn.com.chengmandian.bike.dto.RideOrderPayForm;
import cn.com.chengmandian.bike.mapper.EbRidePenaltyMapper;
import cn.com.chengmandian.bike.model.*;
import cn.com.chengmandian.bike.service.*;
import cn.com.chengmandian.bike.utils.AliPayUtil;
import cn.com.chengmandian.bike.utils.WxPayUtil;
import cn.com.chengmandian.core.common.constants.CommonConstant;
import cn.com.chengmandian.core.common.utils.BillNoUtil;
import cn.com.chengmandian.core.redis.service.RedisService;
import cn.com.chengmandian.core.web.exceptions.BadResponseException;
import cn.com.chengmandian.core.web.pojo.AgentInfo;
import cn.com.chengmandian.core.web.pojo.AgentUser;
import cn.com.chengmandian.core.web.pojo.AjaxResult;
import cn.com.chengmandian.core.web.utils.LocalMapUtil;
import cn.com.chengmandian.core.web.utils.SpringContextUtil;
import cn.com.chengmandian.service.bike.BikePayClient;
import cn.com.chengmandian.service.bike.constants.*;
import cn.com.chengmandian.service.bike.form.BikePayForm;
import cn.com.chengmandian.service.bike.form.BikeRefundForm;
import cn.com.chengmandian.service.bike.form.RidePenaltyRefundForm;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

@Service
public class EbRidePenaltyServiceImpl extends ServiceImpl<EbRidePenaltyMapper, EbRidePenalty> implements IEbRidePenaltyService {

    @Autowired
    private IEbMemberPayService memberPayService;

    @Autowired
    private IEbMemberInfoService memberInfoService;

    @Autowired
    private IEbMemberWalletService memberWalletService;

    @Autowired
    private IEbRideOrderService rideOrderService;

    @Autowired
    private IEbRefundInfoService refundInfoService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private IEbAgentInfoService agentInfoService;

    @Autowired
    private IEbPayAccountService payAccountService;

    @Autowired
    private BikePayClient payClient;

    /**
     * 创建
     * @param rideOrder
     */
    @Override
    public void addByOrder(EbRideOrder rideOrder, BigDecimal money) {
        EbRidePenalty penalty = new EbRidePenalty();
        penalty.setPenaltyNo(BillNoUtil.getSimpleNo("RP-"));
        penalty.setOrderId(rideOrder.getId());
        penalty.setMoney(money);
        penalty.setStatus(RidePenaltyStatusEnum.READY.getCode());
        this.save(penalty);
    }

    /**
     * 骑行订单支付罚款
     *
     * @param clientIp
     * @param rideOrder
     * @return
     */
    @Override
    public AjaxResult payByOrder(String clientIp, EbRideOrder rideOrder, RideOrderPayForm rideOrderPayForm) throws Exception {
        EbRidePenalty ridePenalty = this.getOne(new LambdaQueryWrapper<EbRidePenalty>()
                .eq(EbRidePenalty::getOrderId, rideOrder.getId())
                .last("limit 1"));
        Assert.notNull(ridePenalty, "找不到罚款信息:" + rideOrder.getOrderNo());
        Assert.isTrue(ridePenalty.getStatus().equals(RidePenaltyStatusEnum.READY.getCode()), "罚款状态不正确:" + ridePenalty.getStatus());

        AgentUser agentUser = AuthUtil.getAgentUser();

        EbMemberPay memberPay = memberPayService.createPay(rideOrder.getAreaId(),
                agentUser.getId(),
                MemberPayBusinessTypeEnum.RIDE_PENALTY_PAY,
                ridePenalty.getId(),
                ridePenalty.getMoney(),
                rideOrderPayForm.getPayChannel());

        // 更新部分支付信息
        this.update(new LambdaUpdateWrapper<EbRidePenalty>()
                .set(EbRidePenalty::getPayId, memberPay.getId())
                .set(EbRidePenalty::getPayNo, memberPay.getPayNo())
                .eq(EbRidePenalty::getId, ridePenalty.getId()));

        AgentInfo agentInfo = LocalMapUtil.getAgentInfo();
        EbMemberInfo memberInfo = memberInfoService.getById(agentUser.getId());

        EbAgentInfo info = agentInfoService.getById(agentInfo.getId());
        if (info.getPayAccountId() != null) {
            EbPayAccount payAccount = payAccountService.getPayAccount(info.getPayAccountId(), agentUser.getId());
            if (payAccount != null && (rideOrderPayForm.getPayChannel().equals(PayChannelEnum.WXPAY.getCode()) || rideOrderPayForm.getPayChannel().equals(PayChannelEnum.ALIPAY.getCode()))) {
                PayChannelEnum payChannel = PayChannelEnum.getByCode(rideOrderPayForm.getPayChannel());
                BikePayForm bikePayForm = new BikePayForm();
                bikePayForm.setMemberPayId(memberPay.getId());
                bikePayForm.setPayBusinessType(MemberPayBusinessTypeEnum.RIDE_PENALTY_PAY);
                bikePayForm.setPayChannel(payChannel);
                bikePayForm.setMoney(rideOrder.getMoney());
                bikePayForm.setOpenId(StrUtil.isNotBlank(rideOrderPayForm.getOpenId()) ? rideOrderPayForm.getOpenId() : memberInfo.getOpenId());
                bikePayForm.setAlipayUserId(memberInfo.getAlipayUserId());
                bikePayForm.setAlipayOpenId(memberInfo.getAlipayOpenId());
                bikePayForm.setAreaId(agentInfo.getAreaId());
                bikePayForm.setMemberId(AuthUtil.getAgentUser().getId());
                bikePayForm.setBusinessId(rideOrder.getId());
                bikePayForm.setClientIp(clientIp);
                return payClient.pay(agentInfo.getId(), bikePayForm);
            }
        }

        String notifyUrl = "http://"+ agentInfo.getDomain() + "/api/v1/bikeuser/notify";
        AjaxResult result = null;
        if (rideOrderPayForm.getPayChannel().equals(PayChannelEnum.WXPAY.getCode())) {
            Assert.isTrue(StrUtil.isNotBlank(agentInfo.getWxMchId()), "未开启微信支付");
            if (rideOrderPayForm.getChannelType().equals(ChannelTypeEnum.MINI.getCode())) {
                String openId = StrUtil.isNotBlank(rideOrderPayForm.getOpenId()) ? rideOrderPayForm.getOpenId() : memberInfo.getOpenId();
                Assert.isTrue(StrUtil.isNotBlank(openId), "缺少openid");
                result  = AjaxResult.success(WxPayUtil.jsapiTransactions(
                        agentInfo.getWxMiniAppid(),
                        agentInfo.getWxMchId(),
                        openId,
                        "支付骑行订单",
                        memberPay.getPayNo(),
                        memberPay.getMoney(),
                        agentInfo.getWxKeyPath(),
                        agentInfo.getWxCertPath(),
                        notifyUrl + "/wxpay/pay/" + LocalMapUtil.getAgentInfo().getAgentNo()
                ));

            }
        } else if (rideOrderPayForm.getPayChannel().equals(PayChannelEnum.ALIPAY.getCode())) {
            // 支付宝用户唯一标识user_id 和open_id必须有一个有值
            Assert.isTrue(StrUtil.isNotBlank(memberInfo.getAlipayUserId()) || StrUtil.isNotBlank(memberInfo.getAlipayOpenId()), "用户缺少支付宝用户标识");
            result = AjaxResult.success(AliPayUtil.getTradeCreateRequestParam(
                    agentInfo.getAliMiniAppid(),
                    memberInfo.getAlipayUserId(),
                    memberInfo.getAlipayOpenId(),
                    "支付骑行订单",
                    memberPay.getPayNo(),
                    memberPay.getMoney(),
                    agentInfo.getAliPayPrivateKey(),
                    agentInfo.getAliPayCertPath(),
                    agentInfo.getAliPayPublicCertPath(),
                    agentInfo.getAliPayRootCertPath(),
                    notifyUrl + "/ali/pay/" + LocalMapUtil.getAgentInfo().getAgentNo()
            ));
        }
        if(result == null){
            return AjaxResult.error("暂不支持此支付方式，请使用在线支付！");
        }
        return result;
    }

    /**
     * 罚款支付成功
     * @param memberPay
     */
    @Override
    public void paySuccess(EbMemberPay memberPay) {
        this.update(new LambdaUpdateWrapper<EbRidePenalty>()
                .set(EbRidePenalty::getStatus, CommonConstant.TWO)
                .set(EbRidePenalty::getPayTime, new Date())
                .eq(EbRidePenalty::getId, memberPay.getBusinessId()));

        EbRidePenalty ridePenalty = this.getById(memberPay.getBusinessId());

        // 订单罚款支付成功
        rideOrderService.orderPenaltyPaid(ridePenalty.getOrderId());
    }

    /**
     * 罚款退款
     * @param form
     */
    @Override
    public void refundByOrder(RidePenaltyRefundForm form) {
        String key = SpringContextUtil.getAppName().toUpperCase() + ":BIKE:REFUND:ORDER:" + form.getRideOrderId();
        try {
            if (redisService.hasKey(key)) {
                throw new BadResponseException("该订单正在退款中,请稍等....");
            }
            redisService.set(key, true, 5);
            Assert.isTrue(form.getRefundMoney().compareTo(BigDecimal.ZERO) > 0, "退款金额必须大于0");

            EbRideOrder rideOrder = rideOrderService.getById(form.getRideOrderId());
            Assert.notNull(rideOrder, "找不到骑行订单：" + form.getRideOrderId());

            Assert.isTrue(rideOrder.getPenaltyPayStatus().equals(RideOrderPenaltyPayStatusEnum.COMPLETE.getCode()), "订单罚款支付状态不正确:" + rideOrder.getPenaltyPayStatus());

            // 独立罚单
            EbRidePenalty ridePenalty = this.getOne(new LambdaQueryWrapper<EbRidePenalty>()
                    .eq(EbRidePenalty::getOrderId, form.getRideOrderId()));
            Assert.notNull(ridePenalty, "找不到独立罚单，订单号：" + rideOrder.getOrderNo());

            Assert.isTrue(ridePenalty.getStatus().equals(RidePenaltyStatusEnum.PAID.getCode()), "罚款支付状态不正确：" + ridePenalty.getStatus());

            BigDecimal balance = ridePenalty.getMoney().subtract(rideOrder.getRefundDispatchMoney()).subtract(rideOrder.getRefundHelmetMoney());
            Assert.isTrue(form.getRefundMoney().compareTo(balance) <= 0, "可退款金额不足：" + balance.floatValue());

            if(form.getRefundType().equals(RefundTypeEnum.DISPATCH.getCode())){
                BigDecimal refundDispatchMoney = (ObjectUtil.isNull(rideOrder.getRefundDispatchMoney()) ? BigDecimal.ZERO : rideOrder.getRefundDispatchMoney())
                        .add(form.getRefundMoney());
                if(refundDispatchMoney.compareTo(rideOrder.getDispatchMoney()) > 0){
                    throw new BadResponseException("退款调度费用超出!");
                }
            } else if(form.getRefundType().equals(RefundTypeEnum.HELMET.getCode())){
                BigDecimal refundHelmetMoney = (ObjectUtil.isNull(rideOrder.getRefundHelmetMoney()) ? BigDecimal.ZERO : rideOrder.getRefundHelmetMoney())
                        .add(form.getRefundMoney());
                if(refundHelmetMoney.compareTo(rideOrder.getHelmetPay()) > 0){
                    throw new BadResponseException("退款头盔赔偿费用超出!");
                }
            } else {
                throw new BadResponseException("不支持的退款类型：" + form.getRefundType());
            }

            // 支付记录
            EbMemberPay ebMemberPay = memberPayService.getById(ridePenalty.getPayId());
            Assert.notNull(ebMemberPay, "支付记录信息不存在:" + ridePenalty.getPayId());

            Assert.isTrue(form.getRefundMoney().compareTo((ebMemberPay.getMoney().subtract(ObjectUtil.isNull(ebMemberPay.getRefundMoney()) ? BigDecimal.ZERO : ebMemberPay.getRefundMoney()))) <= 0,
                    "支付记录退款金额超出");

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("refundType",form.getRefundType());

            AgentInfo agentInfo = LocalMapUtil.getAgentInfo();
            String notifyUrl = "http://"+ agentInfo.getDomain() + "/api/v1/bikeuser/notify";
            if (ebMemberPay.getPayChannel().equals(PayChannelEnum.WXPAY.getCode())) {
                // 生成退款支付记录
                EbRefundInfo ebRefundInfo = refundInfoService.createRefund(ebMemberPay.getAreaId(),
                        ebMemberPay.getMemberId(),
                        ebMemberPay.getBusinessId(),
                        ebMemberPay.getId(),
                        ebMemberPay.getFeeRatio(),
                        form.getRefundMoney(),
                        RefundBusinessTypeEnum.RIDE_PENALTY,
                        RefundChannelEnum.WX,
                        form.getRefundReason(),
                        form.getLoginUser(),
                        jsonObject.toJSONString());
                EbMemberInfo ebMemberInfo = memberInfoService.getById(ebMemberPay.getMemberId());
                EbAgentInfo info = agentInfoService.getById(agentInfo.getId());
                if (info.getPayAccountId() != null) {
                    EbPayAccount payAccount = payAccountService.getPayAccount(info.getPayAccountId(), ebMemberPay.getMemberId());
                    if (payAccount != null) {
                        BikeRefundForm refundForm = new BikeRefundForm();
                        refundForm.setBusinessType(RefundBusinessTypeEnum.RIDE_PENALTY);
                        refundForm.setMemberPayId(ebMemberPay.getId());
                        refundForm.setMoney(ebRefundInfo.getMoney());
                        refundForm.setRefundNo(ebRefundInfo.getRefundNo());
                        refundForm.setAlipayUserId(ebMemberInfo.getAlipayUserId());
                        refundForm.setAlipayOpenId(ebMemberInfo.getAlipayOpenId());
                        AjaxResult result = payClient.refund(ebMemberPay.getAgentId(), refundForm);
                        Assert.isTrue(result.isSuccess(), result.getMessage());
                        return;
                    }
                }
                try {
                    WxPayUtil.refund(
                            agentInfo.getWxMchId(),
                            ebRefundInfo.getRefundNo(),
                            ebMemberPay.getPayNo(),
                            "骑行卡订单退款",
                            ebRefundInfo.getMoney(),
                            ebMemberPay.getMoney(),
                            agentInfo.getWxKeyPath(),
                            agentInfo.getWxCertPath(),
                            notifyUrl + "/wx/refund/" + LocalMapUtil.getAgentInfo().getId());
                } catch (Exception ex) {
                    log.error("微信退款失败", ex);
                    throw new BadResponseException("微信退款失败:" + ex.getMessage());
                }
            } else if (ebMemberPay.getPayChannel().equals(PayChannelEnum.ALIPAY.getCode())) {
                // 生成退款支付记录
                EbRefundInfo ebRefundInfo = refundInfoService.createRefund(ebMemberPay.getAreaId(),
                        ebMemberPay.getMemberId(),
                        ebMemberPay.getBusinessId(),
                        ebMemberPay.getId(),
                        ebMemberPay.getFeeRatio(),
                        form.getRefundMoney(),
                        RefundBusinessTypeEnum.RIDE_PENALTY,
                        RefundChannelEnum.ALI,
                        form.getRefundReason(),
                        form.getLoginUser(),
                        jsonObject.toJSONString());
                EbMemberInfo ebMemberInfo = memberInfoService.getById(ebMemberPay.getMemberId());
                EbAgentInfo info = agentInfoService.getById(agentInfo.getId());
                if (info.getPayAccountId() != null) {
                    EbPayAccount payAccount = payAccountService.getPayAccount(info.getPayAccountId(), ebMemberPay.getMemberId());
                    if (payAccount != null) {
                        BikeRefundForm refundForm = new BikeRefundForm();
                        refundForm.setBusinessType(RefundBusinessTypeEnum.RIDE_PENALTY);
                        refundForm.setMemberPayId(ebMemberPay.getId());
                        refundForm.setMoney(ebRefundInfo.getMoney());
                        refundForm.setRefundNo(ebRefundInfo.getRefundNo());
                        refundForm.setAlipayUserId(ebMemberInfo.getAlipayUserId());
                        refundForm.setAlipayOpenId(ebMemberInfo.getAlipayOpenId());
                        AjaxResult result = payClient.refund(ebMemberPay.getAgentId(), refundForm);
                        Assert.isTrue(result.isSuccess(), result.getMessage());
                        return;
                    }
                }
                try {
                    Map<String, String> res = AliPayUtil.getTradeRefundRequestParam(
                            agentInfo.getAliMiniAppid(),
                            ebMemberInfo.getAlipayUserId(),
                            ebMemberInfo.getAlipayOpenId(),
                            "骑行卡订单退款",
                            ebMemberPay.getPayNo(),
                            ebRefundInfo.getRefundNo(),
                            ebRefundInfo.getMoney(),
                            agentInfo.getAliPayPrivateKey(),
                            agentInfo.getAliPayCertPath(),
                            agentInfo.getAliPayPublicCertPath(),
                            agentInfo.getAliPayRootCertPath());
                    ebRefundInfo.setChannelNo(res.get("trade_no"));
                    this.refundSuccess(ebRefundInfo);
                } catch (Exception ex) {
                    log.error("支付宝退款失败", ex);
                    throw new BadResponseException("支付宝退款失败:" + ex.getMessage());
                }
            }

        }catch (Exception ex){
            redisService.del(key);
            throw new BadResponseException(ex.getMessage());
        }

    }

    /**
     * 退款成功
     */
    @Override
    public void refundSuccess(EbRefundInfo refundInfo) {
        EbRidePenalty ridePenalty = this.getById(refundInfo.getBusinessId());
        Assert.notNull(ridePenalty,"订单记录不存在:" + refundInfo.getBusinessId());

        EbMemberPay memberPay = memberPayService.getById(refundInfo.getPayId());

        // 更新罚款状态
        this.update(new LambdaUpdateWrapper<EbRidePenalty>()
                .set(EbRidePenalty::getRefundMoney, memberPay.getRefundMoney())
                .set(memberPay.getStatus().equals(MemberPayStatusEnum.REFUND.getCode()), EbRidePenalty::getStatus, CommonConstant.THREE)
                .eq(EbRidePenalty::getId, ridePenalty.getId()));

        JSONObject jsonObject = JSONObject.parseObject(refundInfo.getData());
        Integer refundType = jsonObject.getInteger("refundType");
        EbRideOrder rideOrder = rideOrderService.getById(ridePenalty.getOrderId());
        // 订单、调度的费用
        BigDecimal refundOrderMoney = (ObjectUtil.isNull(rideOrder.getRefundOrderMoney()) ? BigDecimal.ZERO : rideOrder.getRefundOrderMoney());
        if(refundType.equals(RefundTypeEnum.ORDER.getCode())){
            refundOrderMoney = refundOrderMoney.add(refundInfo.getMoney());
        }
        BigDecimal refundDispatchMoney = (ObjectUtil.isNull(rideOrder.getRefundDispatchMoney()) ? BigDecimal.ZERO : rideOrder.getRefundDispatchMoney());
        if(refundType.equals(RefundTypeEnum.DISPATCH.getCode())){
            refundDispatchMoney = refundDispatchMoney.add(refundInfo.getMoney());
        }
        BigDecimal refundHelmetMoney = (ObjectUtil.isNull(rideOrder.getRefundHelmetMoney()) ? BigDecimal.ZERO : rideOrder.getRefundHelmetMoney());
        if(refundType.equals(RefundTypeEnum.HELMET.getCode())){
            refundHelmetMoney = refundHelmetMoney.add(refundInfo.getMoney());
        }

        BigDecimal refundMoney = refundOrderMoney.add(refundDispatchMoney).add(refundHelmetMoney);
        rideOrderService.update(new LambdaUpdateWrapper<EbRideOrder>()
                .set(refundMoney.compareTo(rideOrder.getMoney()) >= 0, EbRideOrder::getStatus, RideOrderStatusEnum.REFUND.getCode())
                .set(EbRideOrder::getRefundDispatchMoney, refundDispatchMoney)
                .set(EbRideOrder::getRefundHelmetMoney, refundHelmetMoney)
                .set(EbRideOrder::getRefundMoney, refundMoney)
                .eq(EbRideOrder::getId, rideOrder.getId()));
    }
}
